﻿/***************************************************************
 * 开发人员：网魂小兵@http://www.mozlite.com
 * 
 * 目标标本：4.0.30319.239
 * 
 * 最后修改：2011/12/16 17:19:10
 * ************************************************************/
namespace Mozlite.Web.UI
{
    using System;
    using System.Linq;
    using System.Text;
    using System.Web.Mvc;
    using System.Web.Routing;
    using System.Collections.Generic;
    using Mozlite.Common.Configuration;
    using System.Text.RegularExpressions;
    using Mozlite.Common;

    /// <summary>
    /// 路由管理类。
    /// </summary>
    public class RouteManager
    {
        /// <summary>
        /// 初始化类<see cref="T:Mozlite.Themes.Routes"/>。
        /// </summary>
        private RouteManager() { }

        internal static string Replace(string url, string area = null)
        {
            url = url.ToLower();
            if (area != null)
                area += "/";
            url = url.Replace("$root:", area);
            return url + SiteSettings.Default.PageMode.ToExtension();
        }

        private static readonly Regex keyRegex = new Regex("\\{([a-z]+?)\\}", RegexOptions.IgnoreCase | RegexOptions.Compiled);

        private static readonly Dictionary<string, string> urlsCaches = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        private static readonly object locker = new object();

        private static string GetCacheUrl(string key) {
            lock (locker)
            { 
                string url;
                if (urlsCaches.TryGetValue(key, out url))
                    return url;
            }
            return null;
        }

        private static string AddCacheUrl(string key, string url)
        {
            if (string.IsNullOrEmpty(url))
                return null;
            lock (locker)
            {
                if (!urlsCaches.ContainsKey(key))
                    urlsCaches.Add(key, url);
            }
            return url;
        }

        /// <summary>
        /// 格式化URL地址。
        /// </summary>
        /// <param name="name">路由名称。</param>
        /// <param name="values">参数键值对。</param>
        /// <param name="area">区域名称。</param>
        /// <returns>返回URL地址。</returns>
        public static string FormatUrl(string name, object values = null, string area = null)
        {
            return FormatUrl(name, new RouteValueDictionary(values), area);
        }

        /// <summary>
        /// 格式化URL地址。
        /// </summary>
        /// <param name="name">路由名称。</param>
        /// <param name="values">参数键值对。</param>
        /// <param name="area">区域名称。</param>
        /// <returns>返回URL地址。</returns>
        public static string FormatUrl(string name, RouteValueDictionary values = null, string area = null)
        {
            name = GetRouteName(area, name);
            string url = null;
            if (values == null)
            {
                url = GetCacheUrl(name);
                if (url != null)
                    return url;
                url = GetRouteUrl(name, null);
                return AddCacheUrl(name, url);
            }
            return GetRouteUrl(name, values);
        }

        private static string GetRouteUrl(string name, RouteValueDictionary values)
        {
            using (RouteTable.Routes.GetReadLock())
            {
                var route = RouteTable.Routes[name] as System.Web.Routing.Route;
                if (route == null)
                    return "#";
                //throw new Exception("The route named “" + name + "” cannot be found!");

                var url = Globals.GetUrl(keyRegex.Replace(route.Url, match =>
                {
                    string key = match.Groups[1].Value;
                    object value = null;
                    if (values != null && values.ContainsKey(key))
                        value = values[key];
                    if ((value == null || string.IsNullOrEmpty(value.ToString())) && route.Defaults != null && route.Defaults.ContainsKey(key))
                        value = route.Defaults[key];
                    return (value ?? "").ToString();
                }));
                var domainRoute = route as DomainRoute;
                if(domainRoute!=null&&!string.IsNullOrEmpty(domainRoute.Domain))
                    url = Globals.Combine("http://" + domainRoute.Domain, url);
                return url.ToLower();
            }
        }
        
        /// <summary>
        /// 获取首页地址。
        /// </summary>
        /// <param name="area">区域名称。</param>
        /// <returns>返回首页默认地址。</returns>
        public static string GetDefaultUrl(string area = null)
        {
            if (area == null)
                return SiteSettings.Default.SiteUrl;
            string key = GetRouteName(area, "Index");
            string url = GetCacheUrl(key);
            if (url == null)
                url = AddCacheUrl(key, GetRouteDefaultUrl(area));
            return url;
        }

        private static string GetRouteDefaultUrl(string area = null)
        {
            using (RouteTable.Routes.GetReadLock())
            {
                var route = RouteTable.Routes[GetRouteName(area, "Index")] as DomainRoute;
                var url = SiteSettings.Default.SiteUrl + "/" + area;
                if (route != null)
                    url = "http://" + route.Domain;
                return url.ToLower();
            }
        }

        /// <summary>
        /// 获取唯一路由名称。
        /// </summary>
        /// <param name="area">区域名称。</param>
        /// <param name="name">名称。</param>
        /// <returns>返回路由名称。</returns>
        public static string GetRouteName(string area, string name)
        {
            if (string.IsNullOrEmpty(area))
                return name.ToLower();
            return (area + "::" + name).ToLower();
        }

        /// <summary>
        /// 注册路由集合。
        /// </summary>
        /// <param name="routes">路由集合实例对象。</param>
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            foreach (var route in Globals.FindType<BaseRouteRegistration>())
            {
                route.RouteRegister(routes);
            }

            routes.BeginRegister();

            //首页
            routes.EndRegister();
        }
    }
}